package cloud.smalla.utils;

/**
 * 布隆过滤器工具类
 *
 * @author zeng
 */
public class BloomFilterUtil {

    public static final String PROJECT_PRE = "proid";

    private static final RedisUtils REDIS = RedisUtils.getInstance();
    /**
     * 布隆过滤器key
     */
    private static final String USER_ID_BIT_SET = "bloom_filter_key";
    /**
     * 初始化的集合长度
     */
    private static final int MAX_LENGTH = Integer.MAX_VALUE;
    /**
     * 准备hash计算次数
     */
    private static final int HASH_LENGTH = 5;
    /**
     * 准备自定义哈希算法需要用到的质数，因为一条数据需要hash计算5次 且5次的结果要不一样
     */
    private static final int[] PRIME_NUMS = new int[]{17, 19, 29, 31, 37};

    /**
     * 添加元素到bitSet中
     *
     * @param key 添加的key
     */
    public static void addKey(String key) {
        for (int i : PRIME_NUMS) {
            // 计算hashcode
            int hashcode = hash(key, i);
            // 计算映射在bitset上的位置
            int bitIndex = hashcode & (MAX_LENGTH - 1);
            REDIS.setBit(USER_ID_BIT_SET, bitIndex, true);
        }
    }

    /**
     * 判断bitSet中是否有被查询的的key(经过hash处理之后的)
     *
     * @param key
     * @return
     */
    public static boolean hasKey(String key) {
        for (int i : PRIME_NUMS) {
            // 计算hashcode
            int hashcode = hash(key, i);
            // 计算映射在bitset上的位置
            int bitIndex = hashcode & (MAX_LENGTH - 1);
            // 只要有一个位置对应不上，则返回false
            if (!REDIS.getBit(USER_ID_BIT_SET, bitIndex)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 自定义hash函数
     *
     * @param key   key
     * @param prime 计算的hash质数
     * @return 返回计算的hash值
     */
    private static int hash(String key, int prime) {
        int h = 0;
        char[] value = key.toCharArray();
        if (h == 0 && value.length > 0) {
            char[] val = value;
            for (int i = 0; i < value.length; i++) {
                h = prime * h + val[i];
            }
        }
        return h;
    }
}